package com.shrcl.engineerprocess.domain.impl;

import com.google.common.base.Objects;
import com.shrcl.engineerprocess.domain.ActorsDAO;
import com.shrcl.engineerprocess.domain.Engineer;
import com.shrcl.engineerprocess.domain.EngineerProject;
import com.shrcl.engineerprocess.domain.EngineerProjectAssignment;
import com.shrcl.engineerprocess.domain.EngineerProjectJob;
import com.shrcl.engineerprocess.domain.EngineerWorkOrder;
import com.shrcl.engineerprocess.domain.EngineerWorkOrderStatus;
import com.shrcl.engineerprocess.domain.WorkOrderPendingRequestTask;
import com.shrcl.engineerprocess.domain.impl.EngineerImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerProjectAssignmentImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerProjectJobImpl;
import com.shrcl.engineerprocess.domain.impl.WorkOrderPendingRequestTaskImpl;
import com.shrcl.engineerprocess.domain.proxy.EngineerWorkOrderProxy;
import com.shrct.businessprocess.organization.RCEmployee;
import com.uniquesoft.uidl.validation.Validates;
import edu.fudan.langlab.domain.statemachine.ModelObjectLogService;
import edu.fudan.langlab.domain.task.TSKTask;
import edu.fudan.langlab.domain.task.TSKTaskDAO;
import edu.fudan.langlab.domain.task.TSKTaskOwner;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IObjectFactory;
import edu.fudan.mylang.utils.DateUtil;
import java.util.Collection;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.InputOutput;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;
import org.springframework.beans.factory.BeanFactory;

@Entity
@DiscriminatorValue("ENGINEERWORKORDER_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "engineerworkorder")
public class EngineerWorkOrderImpl extends BaseModelObject implements EngineerWorkOrder {
  public EngineerWorkOrderImpl() {
    super();
  }
  
  public EngineerWorkOrderImpl(final EngineerProjectJob projectJob) {
    super();
    this.projectJob = projectJob;
  }
  
  private EngineerWorkOrderStatus Status;
  
  public EngineerWorkOrderStatus getStatus() {
    return this.Status;
  }
  
  private ModelObjectLogService getModelObjectLogService() {
    return getBeanFactory().getBean(ModelObjectLogService.class);
  }
  
  private void _start() {
    
    this.checkValid();
    Status=EngineerWorkOrderStatus.executing;
  }
  
  public void start() {
    if(Status==null){
    	_start();
    	getModelObjectLogService().createLog(this,"Status","Start");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).fireStarted(this);					
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("allready started");
    }
  }
  
  private void _$startexecute(final EngineerProjectAssignment projectAssignment) {
    
    Status=EngineerWorkOrderStatus.executing;
    Boolean _isCreated = this.projectJob.isCreated();
    if ((_isCreated).booleanValue()) {
      this.projectJob.execute();
    }
  }
  
  public void $startexecute(final EngineerProjectAssignment projectAssignment) {
    if(Status==EngineerWorkOrderStatus.created){
    	_$startexecute(projectAssignment);
    	getModelObjectLogService().createLog(this,"Status","$startexecute");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).fire$startexecute(this,projectAssignment);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _$taskFinish(final EngineerProjectAssignment projectAssignment) {
    
    boolean _isAllTaskFinishedorCancelled = this.isAllTaskFinishedorCancelled();
    if (_isAllTaskFinishedorCancelled) {
      InputOutput.<String>println("======>workorder finished");
      Status=EngineerWorkOrderStatus.committed;
    } else {
    }
  }
  
  public void $taskFinish(final EngineerProjectAssignment projectAssignment) {
    if(Status==EngineerWorkOrderStatus.executing){
    	_$taskFinish(projectAssignment);
    	getModelObjectLogService().createLog(this,"Status","$taskFinish");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).fire$taskFinish(this,projectAssignment);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _$taskCancel(final EngineerProjectAssignment projectAssignment) {
    
    boolean _isAllTaskFinishedorCancelled = this.isAllTaskFinishedorCancelled();
    if (_isAllTaskFinishedorCancelled) {
      InputOutput.<String>println("======>workorder finished");
      Status=EngineerWorkOrderStatus.committed;
    }
  }
  
  public void $taskCancel(final EngineerProjectAssignment projectAssignment) {
    if(Status==EngineerWorkOrderStatus.executing){
    	_$taskCancel(projectAssignment);
    	getModelObjectLogService().createLog(this,"Status","$taskCancel");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).fire$taskCancel(this,projectAssignment);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _pendingApply() {
    
    this.createPendingTask();
    Status=EngineerWorkOrderStatus.pendingApply;
  }
  
  public void pendingApply() {
    if(Status==EngineerWorkOrderStatus.executing){
    	_pendingApply();
    	getModelObjectLogService().createLog(this,"Status","pendingApply");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).firePendingApply(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _addAssignment(final Procedure1<? super EngineerProjectAssignment> init) {
    
    EngineerProjectAssignment _createAndAddtoProjectAssignments = this.createAndAddtoProjectAssignments();
    final Procedure1<EngineerProjectAssignment> _function = new Procedure1<EngineerProjectAssignment>() {
        public void apply(final EngineerProjectAssignment it) {
          init.apply(it);
        }
      };
    EngineerProjectAssignment _doubleArrow = ObjectExtensions.<EngineerProjectAssignment>operator_doubleArrow(_createAndAddtoProjectAssignments, _function);
    final Procedure1<EngineerProjectAssignment> _function_1 = new Procedure1<EngineerProjectAssignment>() {
        public void apply(final EngineerProjectAssignment ass) {
          boolean _or = false;
          boolean _equals = Objects.equal(EngineerWorkOrderImpl.this.startDate, null);
          if (_equals) {
            _or = true;
          } else {
            Date _startDate = ass.getStartDate();
            boolean _greaterThan = (EngineerWorkOrderImpl.this.startDate.compareTo(_startDate) > 0);
            _or = (_equals || _greaterThan);
          }
          if (_or) {
            Date _startDate_1 = ass.getStartDate();
            EngineerWorkOrderImpl.this.startDate = _startDate_1;
          }
          boolean _or_1 = false;
          boolean _equals_1 = Objects.equal(EngineerWorkOrderImpl.this.endDate, null);
          if (_equals_1) {
            _or_1 = true;
          } else {
            Date _endDate = ass.getEndDate();
            boolean _lessThan = (EngineerWorkOrderImpl.this.endDate.compareTo(_endDate) < 0);
            _or_1 = (_equals_1 || _lessThan);
          }
          if (_or_1) {
            Date _endDate_1 = ass.getEndDate();
            EngineerWorkOrderImpl.this.endDate = _endDate_1;
          }
        }
      };
    ObjectExtensions.<EngineerProjectAssignment>operator_doubleArrow(_doubleArrow, _function_1);
  }
  
  public void addAssignment(final Procedure1<? super EngineerProjectAssignment> init) {
    if(Status==EngineerWorkOrderStatus.executing){
    	_addAssignment(init);
    	getModelObjectLogService().createLog(this,"Status","addAssignment");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).fireAddAssignment(this,init);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _delAssignment(final EngineerProjectAssignment assignment) {
    
    this.removeFromProjectAssignments(assignment);
  }
  
  public void delAssignment(final EngineerProjectAssignment assignment) {
    if(Status==EngineerWorkOrderStatus.executing){
    	_delAssignment(assignment);
    	getModelObjectLogService().createLog(this,"Status","delAssignment");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).fireDelAssignment(this,assignment);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _commitFinish() {
    
    Status=EngineerWorkOrderStatus.committed;
  }
  
  public void commitFinish() {
    if(Status==EngineerWorkOrderStatus.executing){
    	_commitFinish();
    	getModelObjectLogService().createLog(this,"Status","commitFinish");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).fireCommitFinish(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _finish() {
    
    Status=EngineerWorkOrderStatus.finished;
    this.projectJob.$workOrderFinish();
  }
  
  public void finish() {
    if(Status==EngineerWorkOrderStatus.committed){
    	_finish();
    	getModelObjectLogService().createLog(this,"Status","finish");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).fireFinish(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _pendingApprove() {
    
    this.cancelAllTasks();
    Status=EngineerWorkOrderStatus.pending;
  }
  
  public void pendingApprove() {
    if(Status==EngineerWorkOrderStatus.pendingApply){
    	_pendingApprove();
    	getModelObjectLogService().createLog(this,"Status","pendingApprove");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).firePendingApprove(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _pendingReject() {
    
    Status=EngineerWorkOrderStatus.executing;
  }
  
  public void pendingReject() {
    if(Status==EngineerWorkOrderStatus.pendingApply){
    	_pendingReject();
    	getModelObjectLogService().createLog(this,"Status","pendingReject");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerWorkOrderEventsManager.class).firePendingReject(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  public Boolean isExecuting() {
    return com.shrcl.engineerprocess.domain.EngineerWorkOrderStatus.executing==Status;
  }
  
  public Boolean isPending() {
    return com.shrcl.engineerprocess.domain.EngineerWorkOrderStatus.pending==Status;
  }
  
  public Boolean isCommitted() {
    return com.shrcl.engineerprocess.domain.EngineerWorkOrderStatus.committed==Status;
  }
  
  public Boolean isFinished() {
    return com.shrcl.engineerprocess.domain.EngineerWorkOrderStatus.finished==Status;
  }
  
  public Boolean isPendingApply() {
    return com.shrcl.engineerprocess.domain.EngineerWorkOrderStatus.pendingApply==Status;
  }
  
  public Boolean isCreated() {
    return com.shrcl.engineerprocess.domain.EngineerWorkOrderStatus.created==Status;
  }
  
  @JoinColumn(name = "projectJob_id")
  @ManyToOne(targetEntity = EngineerProjectJobImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private EngineerProjectJob projectJob;
  
  public EngineerProjectJob getProjectJob() {
    return this.projectJob;
  }
  
  public EngineerWorkOrder setProjectJob(final EngineerProjectJob projectJob) {
    this.projectJob = projectJob;
    return this;			
    
  }
  
  @JoinColumn(name = "engineer_id")
  @ManyToOne(targetEntity = EngineerImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private Engineer engineer;
  
  public Engineer getEngineer() {
    return this.engineer;
  }
  
  public EngineerWorkOrder setEngineer(final Engineer engineer) {
    this.engineer = engineer;
    return this;			
    
  }
  
  private String sid;
  
  public String getSid() {
    return this.sid;
  }
  
  public EngineerWorkOrder setSid(final String sid) {
    this.sid = sid;
    return this;			
    
  }
  
  private Date startDate;
  
  public Date getStartDate() {
    return this.startDate;
  }
  
  public EngineerWorkOrder setStartDate(final Date startDate) {
    this.startDate = startDate;
    return this;			
    
  }
  
  private Date endDate;
  
  public Date getEndDate() {
    return this.endDate;
  }
  
  public EngineerWorkOrder setEndDate(final Date endDate) {
    this.endDate = endDate;
    return this;			
    
  }
  
  @OneToMany(targetEntity = EngineerProjectAssignmentImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, mappedBy = "workOrder")
  private Collection<EngineerProjectAssignment> projectAssignments = new java.util.ArrayList<com.shrcl.engineerprocess.domain.EngineerProjectAssignment>();;
  
  public Collection<EngineerProjectAssignment> getProjectAssignments() {
    return this.projectAssignments;
  }
  
  public EngineerProjectAssignment createAndAddtoProjectAssignments() {
    getProjectAssignments().size();
    com.shrcl.engineerprocess.domain.EngineerProjectAssignment engineerProjectAssignment = new com.shrcl.engineerprocess.domain.impl.EngineerProjectAssignmentImpl(this);
    getObjectFactory().create(engineerProjectAssignment);
    getProjectAssignments().add(engineerProjectAssignment);
    engineerProjectAssignment.start();
    return engineerProjectAssignment;
    
  }
  
  public EngineerProjectAssignment createAndAddtoProjectAssignments(final Procedure1<EngineerProjectAssignment> updater) {
    getProjectAssignments().size();
    com.shrcl.engineerprocess.domain.EngineerProjectAssignment engineerProjectAssignment = new com.shrcl.engineerprocess.domain.impl.EngineerProjectAssignmentImpl(this);
    getObjectFactory().create(engineerProjectAssignment);
    getProjectAssignments().add(engineerProjectAssignment);
    updater.apply(engineerProjectAssignment);
    engineerProjectAssignment.start();
    return engineerProjectAssignment;
    
  }
  
  public EngineerWorkOrder removeAllProjectAssignments() {
    for(EngineerProjectAssignment obj : this.projectAssignments){
    	getObjectFactory().delete(obj);
    }
    this.projectAssignments.clear();
    return this;	
    
  }
  
  public EngineerWorkOrder removeFromProjectAssignments(final EngineerProjectAssignment engineerProjectAssignment) {
    this.projectAssignments.remove(engineerProjectAssignment);
    getObjectFactory().delete(engineerProjectAssignment);
    return this;
    
  }
  
  private void createPendingTask() {
    BeanFactory _beanFactory = this.getBeanFactory();
    final TSKTaskDAO taskDAO = _beanFactory.<TSKTaskDAO>getBean(TSKTaskDAO.class);
    BeanFactory _beanFactory_1 = this.getBeanFactory();
    final ActorsDAO actorsDAO = _beanFactory_1.<ActorsDAO>getBean(ActorsDAO.class);
    EngineerProject _engineerProject = this.projectJob.getEngineerProject();
    Engineer _projectManager = _engineerProject.getProjectManager();
    RCEmployee _employee = _projectManager==null?(RCEmployee)null:_projectManager.getEmployee();
    final TSKTaskOwner tskOwner = actorsDAO.asTSKTaskOwner(_employee);
    boolean _notEquals = (!Objects.equal(tskOwner, null));
    Validates.Assert(_notEquals, "\u9879\u76EE\u7ECF\u7406\u4E0D\u80FD\u4E3A\u7A7A");
    final Procedure1<TSKTask> _function = new Procedure1<TSKTask>() {
        public void apply(final TSKTask it) {
          Date _now = DateUtil.now();
          it.setGenDate(_now);
          Date _now_1 = DateUtil.now();
          it.setStartTime(_now_1);
          it.start();
          it.startProcess();
        }
      };WorkOrderPendingRequestTask workOrderPendingRequestTask=WorkOrderPendingRequestTaskImpl.create(getObjectFactory());
    final Procedure1<WorkOrderPendingRequestTask> _function_1 = new Procedure1<WorkOrderPendingRequestTask>() {
        public void apply(final WorkOrderPendingRequestTask it) {
          it.setEngineerWorkOrder(EngineerWorkOrderImpl.this);
          it.addOwner(tskOwner);
        }
      };
    WorkOrderPendingRequestTask _doubleArrow = ObjectExtensions.<WorkOrderPendingRequestTask>operator_doubleArrow(workOrderPendingRequestTask, _function_1);
    taskDAO.createTask(_function, _doubleArrow);
  }
  
  public boolean isAllTaskFinishedorCancelled() {
    final Function1<EngineerProjectAssignment,Boolean> _function = new Function1<EngineerProjectAssignment,Boolean>() {
        public Boolean apply(final EngineerProjectAssignment it) {
          boolean _or = false;
          Boolean _isFinished = it.isFinished();
          if ((_isFinished).booleanValue()) {
            _or = true;
          } else {
            Boolean _isCancelled = it.isCancelled();
            _or = ((_isFinished).booleanValue() || (_isCancelled).booleanValue());
          }
          return Boolean.valueOf(_or);
        }
      };
    boolean _forall = IterableExtensions.<EngineerProjectAssignment>forall(this.projectAssignments, _function);
    return _forall;
  }
  
  public void cancelAllTasks() {
    final Function1<EngineerProjectAssignment,Boolean> _function = new Function1<EngineerProjectAssignment,Boolean>() {
        public Boolean apply(final EngineerProjectAssignment it) {
          Boolean _isExecuting = it.isExecuting();
          return _isExecuting;
        }
      };
    Iterable<EngineerProjectAssignment> _filter = IterableExtensions.<EngineerProjectAssignment>filter(this.projectAssignments, _function);
    final Procedure1<EngineerProjectAssignment> _function_1 = new Procedure1<EngineerProjectAssignment>() {
        public void apply(final EngineerProjectAssignment it) {
          it.cancel();
        }
      };
    IterableExtensions.<EngineerProjectAssignment>forEach(_filter, _function_1);
  }
  
  public String getRCProjectName() {
    String _rCProjectName = this.projectJob.getRCProjectName();
    return _rCProjectName;
  }
  
  public String getRCProjectCode() {
    String _rCProjectCode = this.projectJob.getRCProjectCode();
    return _rCProjectCode;
  }
  
  public static EngineerWorkOrder create(final EngineerProjectJob projectJob, final IObjectFactory objectFactory) {
    com.shrcl.engineerprocess.domain.EngineerWorkOrder engineerWorkOrder = new com.shrcl.engineerprocess.domain.impl.EngineerWorkOrderImpl(
    	projectJob
    );
    objectFactory.create(engineerWorkOrder);
    engineerWorkOrder.start();
    return engineerWorkOrder;			
    
  }
  
  public static EngineerWorkOrder createEngineerWorkOrderImpl(final EngineerProjectJob projectJob, final IObjectFactory objectFactory, final Procedure1<EngineerWorkOrder> init) {
    com.shrcl.engineerprocess.domain.EngineerWorkOrder engineerWorkOrder = new com.shrcl.engineerprocess.domain.impl.EngineerWorkOrderImpl(
    	projectJob
    );
    objectFactory.create(engineerWorkOrder);
    init.apply(engineerWorkOrder);
    engineerWorkOrder.start();
    
    return engineerWorkOrder;			
    
  }
  
  public EngineerWorkOrderProxy toProxy() {
    com.shrcl.engineerprocess.domain.proxy.EngineerWorkOrderProxy proxy = new com.shrcl.engineerprocess.domain.proxy.EngineerWorkOrderProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    proxy.setStatus(this.getStatus().name());
    return proxy;
    
  }
}
